﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AlgoImpl.Constraints;
using Utilities.GlobalData;

namespace AlgoImpl
{
    public class ThirdStepManager : StepManagerAbstract
    {
        private Dictionary<int, eConstraints> m_ConstraintsOrder = new Dictionary<int, eConstraints>()
        {
            { 1, eConstraints.MAXSHIFTSOFWORKER},
            { 2, eConstraints.SHIFTFORBIDENFORWORKER},
            { 3, eConstraints.PERIODBETWEENSHIFTS}
        };

        public ThirdStepManager(ShiftRequests sr, int numOfIterations)
        {
            MRequests = sr;
            m_Converter = new Converter();
            m_AlgoExecuter = new AlgoExecuter();
            m_NumOfIterations = numOfIterations;

        }

        protected override void preperations()
        { }

        protected override void convertToGraph()
        { }

        protected override void analyzeResults()
        { }

        protected override void runAlgo()
        {
            const bool k_CheckConstrants = true;
            int maxNumOfIterations = m_ConstraintsOrder.Keys.Count;
            int numOfIterations = 1; 
            setWorkersToShifts(k_CheckConstrants);
            while (!allShiftsAreFull() && numOfIterations < maxNumOfIterations)
            {
                removeConstraint(m_ConstraintsOrder[numOfIterations]);
                //Logger.Instance.WriteToLog(string.Format("constraint {0} removed", m_ConstraintsOrder[numOfIterations].ToString()));
                setWorkersToShifts(k_CheckConstrants);
                numOfIterations++;
            }
            dealWithPeriodBetweenShiftsConstraint();
            if (!allShiftsAreFull())
            {
                setWorkersToShifts(!k_CheckConstrants);
            }
        }

        private void dealWithPeriodBetweenShiftsConstraint()
        {
            const int k_IndexOfCons = 3;

            while (!allShiftsAreFull() && ConstraintsChecker.Instance.Constraints.Constrains
                [eConstraints.PERIODBETWEENSHIFTS].Value > 0)
            {
                removeConstraint(m_ConstraintsOrder[k_IndexOfCons]);
                setWorkersToShifts(true);
            }
        }

        private void setWorkersToShifts(bool isToCheckConstraints)
        {
             foreach (string shiftId in getAllShifts())
             {
                    foreach (string workerId in getAllWorkers())
                    {
                        Worker worker = SharedData.Instance.GetWorkerById(workerId);
                        Shift shift = SharedData.Instance.GetShiftById(shiftId);
                        if (isToCheckConstraints)
                        {
                            ConstraintsChecker.Instance.InitializeWorkerAndShift(workerId, shiftId);
                            if (ConstraintsChecker.Instance.CheckAllConstraints(MRequests))
                            {
                                worker.AddShift(shiftId);
                                shift.AddWorker(workerId);
                            }
                        }
                        else
                        {
                            if (!SharedData.Instance.GetShiftById(shiftId).IsFull())
                            {
                                worker.AddShift(shiftId);
                                shift.AddWorker(workerId);
                            }
                        }
                    }
                }
        }

        private void removeConstraint(eConstraints eConstraint)
        {
            switch (eConstraint)
            {
                case eConstraints.MAXSHIFTSOFWORKER:
                    ConstraintsChecker.Instance.Constraints.ChangeSingleConstraint
                        (eConstraint, false, SingleConstraint.k_SingForNonValue);
                    break;
                case eConstraints.SHIFTFORBIDENFORWORKER:
                    ConstraintsChecker.Instance.Constraints.ChangeSingleConstraint
                         (eConstraint, false, SingleConstraint.k_SingForNonValue);
                    break;
                case eConstraints.PERIODBETWEENSHIFTS:
                    if (ConstraintsChecker.Instance.Constraints.Constrains[eConstraints.PERIODBETWEENSHIFTS].Value > 0)
                    {
                        ConstraintsChecker.Instance.Constraints.ChangeSingleConstraint
                            (eConstraint, true, (ConstraintsChecker.Instance.Constraints.Constrains
                                [eConstraints.PERIODBETWEENSHIFTS].Value - 1));
                    }
                    else
                    {
                        ConstraintsChecker.Instance.Constraints.ChangeSingleConstraint(eConstraint, false, 0);
                    }
                    break;
            }   
        }

        protected override void finalize()
        {
            updateGlobalResultData(eStepThatGotShift.THIRD);
        }

        private bool allShiftsAreFull()
        {
            bool areAllFull = true;
            foreach (string shiftId in SharedData.Instance.GetAllShiftsIds())
            {
                if (!SharedData.Instance.GetShiftById(shiftId).IsFull())
                {
                    areAllFull = false;
                    break;
                }
            }
            return areAllFull;
        }
    }
}
